package com.migu.rbac.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SercurityConfig extends WebSecurityConfigurerAdapter {
    @Value("${security.authentication}")
    private String authentication;

    @Value("${security.antMatchers}")
    private String antMatchers;

    @Autowired
    private DaoSecurityMetadataSource daoSecurityMetadataSource;

    @Autowired
    private UrlAccessDecisionManager decisionManager;

    @Bean
    public Http401AuthenticationEntryPoint securityException401EntryPoint() {
        return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
    }

    @Autowired
    private Http401AuthenticationEntryPoint authEntrypoint;


    private final Logger log = LoggerFactory.getLogger(SercurityConfig.class);

    //创建jwt认证的Filter Bean
    @Bean
    public JWTAuthorizeFilter jwtAuthorizeFilterBean() throws Exception {
        return new JWTAuthorizeFilter();
    }

    @Override
    public void configure(WebSecurity web) {
        String[] split = antMatchers.split(",");
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**")
                .antMatchers("/health")
                .antMatchers("/swagger-ui.html")
                .antMatchers("/swagger-resources/**")
                .antMatchers("/webjars/springfox-swagger-ui/**/*.{js,css,html}")
                .antMatchers(split);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        log.info("EnableAuthentication:" + authentication);
        http
                .csrf().disable()
                .headers().frameOptions().disable()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        if (authentication.equals("enable")) {
            //对指定的请求进行权限设置
            http
                    // 除上面外的所有请求全部需要鉴权认证
                    .authorizeRequests()
                    // 自定义FilterInvocationSecurityMetadataSource
                    .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                        @Override
                        public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                            o.setSecurityMetadataSource(daoSecurityMetadataSource);
                            o.setAccessDecisionManager(decisionManager);
                            return o;
                        }
                    })
                    //实现将未认证过的请求，直接返回401，而不返回403
                    .and()
                    .exceptionHandling().authenticationEntryPoint(authEntrypoint)
                    .and()
                    //在HttpSecurity中增加Filter Bean，必须传入Singletone的bean
                    .addFilterBefore(jwtAuthorizeFilterBean(), UsernamePasswordAuthenticationFilter.class)
                    //对于Actuator的Endpoint启动Basic认证
                    .authorizeRequests()
                    .antMatchers("/admin/shutdown").authenticated().and().httpBasic();
        }

    }
}
